import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

import javax.swing.JFileChooser;


public class FtpRequest implements Runnable {

        private Socket socket;
        private String pseudo;
        private String mdp;
        private String repertoire;
        private String repertoireClient;
        private Boolean attenteMdp;
        private Boolean connecter;
        private int port;
        private String type;
        private int mode; //0:Actif , 1:Passif
       
        private int portPassiv;
        PrintWriter ostream;
        BufferedReader istream;
       
        @Override
        public void run() {
                
                try {
                        
                        /* Connexion établie : 
                         * _ obtention du flot de données sortantes : bytes
                         * _PrintWriter : création d’un stream convertissant les bytes en chaînes de caractères
                         */     
                        OutputStream out = this.socket.getOutputStream();
                        ostream = new PrintWriter(out);
                        
                        /* Obtention d'un flux de données d'entrée.
                         * _ InputStreamReader : création d’un stream convertissant les bytes reçus en char.
                         * _ BufferedReader : création d’un stream de lecture avec tampon: pour lire ligne par ligne dans un stream de caractères.
                         */
                        
                        InputStream in = socket.getInputStream();
                        InputStreamReader reader = new InputStreamReader(in);
                        istream = new BufferedReader(reader);
                        
                        try {
                                System.out.println("On entre dans le run !\n");                         
                                
//                              String s = "220 test\n";    
//                              byte[] bytes = s.getBytes();
//                              DataOutputStream w = new DataOutputStream(out);
//                              w.writeBytes(s);
//                              w.flush();
                                                                
                                ostream.write("220 Service pret pour un nouvel utilisateur.\n");
                                ostream.flush();
                        
                                while (true){
                                        
                                                try {
                                                        System.out.println("en attente d'une commande...\n");
//                                                                                                      
//                                              char[] cbuf =  new char[2018]; 
//                                      
//                                              istream.read(cbuf,0,2047);
//                                              System.out.println("read...\n");
//                                                      char[] cbuf = null;
//                                                      int i;
//                                                      while (( i = istream.read(cbuf)) != -1) {
                                                                                                                                                                                                                
                                                        //for(int i = 0;i <cbuf.length;i++) System.out.println("cbuf:"+cbuf[i]);
                                                        String commande = istream.readLine();
                                                                                                        
                                                        System.out.println("commande recu !\n");                                                        
                                                        System.out.println("commande client :"+commande+"\n");
                                                        
                                                        //on envoie le message à processRequest.
                                                        String reponseFtpRequest = this.processRequest(commande);
                                                                                        
                                                        //on retourne la reponse au client ftp.
                                                        try {
                                                                ostream.write(reponseFtpRequest);
                                                                ostream.flush();                
                                                        } catch (Exception e) {
                                                                e.printStackTrace();
                                                        }                                                       
                                                                                                
                                                } catch (IOException e) {
                                                        // TODO Auto-generated catch block
                                                        e.printStackTrace();
                                                }
                                                
                                        
                                } //while
                                
                        } finally {
                                ostream.close(); 
                                istream.close();
                        }
                        
                }               
                catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }               
        }
       
        public FtpRequest(Socket socket) {
                this.socket = socket;          
                this.pseudo = "";
                this.mdp = "";
                this.connecter = true; // A CHANGER
                this.attenteMdp = false;
                this.repertoire = Serveur.REPERTOIRE;
                this.repertoireClient = "/";
                this.port = 0;
                this.type = "";
                this.mode = -1;
                new Thread(this).start();
        }
       
        public String processRequest(String messageClient) {
                //msg[0] -> code
                //msg[1] -> message
                String[] msg = messageClient.split(" ");
                /*String msgTransfert = "";
                if(msg.length >= 2){
                        msgTransfert = msg[1];
                }*/
               
                String reponse = "";
                if (msg[0].equals("USER")) {
                        reponse = processUSER(msg[1]);
                } else if (msg[0].equals("PASS")) {
                        reponse = processPASS(msg[1]);
                } else if (msg[0].equals("RETR")) {
                        reponse = processRETR(msg[1]);
                } else if (msg[0].equals("STOR")) {
                        reponse = processSTOR(msg[1],msg[2]);
                } else if (msg[0].equals("LIST")) {
                        reponse = processLIST();
                } else if (msg[0].equals("QUIT")) {
                        reponse = processQUIT();
                } else if (msg[0].equals("PORT")) {
                        reponse = processPORT(msg[1]);
                } else if (msg[0].equals("TYPE")) {
                        reponse = processTYPE(msg[1]);
                } else if (msg[0].equals("PWD")) {
                        reponse = processPWD();        
                } else if(msg[0].equals("CWD")){
                        reponse = processCWD(msg[1]);
                } else if (msg[0].equals("EPRT")) {
                        reponse = processEPRT(msg[1]);
                } else if (msg[0].equals("EPSV")) {
                        reponse = processEPSV();
                } else if (msg[0].equals("SYST")) {
                        reponse = "215 WINDOWS 7 \n";
                }
                else {
                        reponse = "200 Commande non implémentée.\n";
                }
               
                return reponse;
        }
       
        public String processUSER(String message) {
                String loginTest = "toto";
                String reponse;        
               
                if (message.equals(loginTest)) {
                        // Mettre le login dans une variable account

                        /* if(true){ */// - si besoin d'un mdp
                        this.pseudo = message;
                        this.attenteMdp = true;
                        reponse = "331 Nom d'utilisateur correct, en attente du mot de passe.\n";
                        /*
                         * }else{ //- si pas besoin d'un mdp reponse = "230"; //Reponse
                         * "Ok t'es log" }
                         */
                } else {
                        reponse = "332 Besoin d'un compte de connexion.\n";
                }
                return reponse;
        }
       
        public String processPASS(String message) {
                String passTest = "toto";
                String reponse;

                if (attenteMdp) {
                        if (message.equals(passTest)) {
                                this.attenteMdp = false;
                                this.mdp = message;
                                this.connecter = true;
                                reponse = "230 Utilisateur connecté après identification.\n";
                        } else {
                                reponse = "332 Besoin d'un compte de connexion.\n";
                                // reponse = "530"; //Reponse "t'es pas log"
                        }
                } else {
                        reponse = "503 Séquence de commande invalide.\n";
                }
                return reponse;
        }
       
        public String processRETR(String message) {
                String reponse;
                BufferedOutputStream bos = null;
                        DataOutputStream dataOut = null;
                        
                        InetAddress ipClientFTP = this.socket.getInetAddress();
                        Socket socket2 = null;
                        try {
                                socket2 = new Socket(ipClientFTP,this.portPassiv);
                        } catch (IOException e2) {
                                e2.printStackTrace();
                        }
                        
                        
                if(this.connecter){ //Connecter
                        File folder = new File(this.repertoire);
                        String[] listeFichier = folder.list();
                        boolean exist = false;
                       
                        for(int i=0;i<listeFichier.length;i++){
                                if(listeFichier[i].equals(message)){
                                        exist = true;
                                }
                        }
                       
                        if(exist){//Envoi du fichier
                               System.out.println(" COUCOU ");

                                        InputStream is;
                                        try {
                                                is = new FileInputStream(this.repertoire + "/" + message);
                                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                        int reads = is.read();
                                       
                                        while(reads != -1){
                                            baos.write(reads);
                                            reads = is.read();
                                        }
                                     
                                        byte[] b = baos.toByteArray();
                                       
                                        try {
                                                
                                                        ostream.write("150 begin\n");
                                                        ostream.flush();
                                                        
                                                        bos = new BufferedOutputStream(socket2.getOutputStream());
                                                        dataOut = new DataOutputStream (bos);
                                                        
                                                        byte[] buf = new byte[1024];
                                                        int bytesRead;
                                                        while ((bytesRead = is.read(buf)) > 0) {
                                                                    //output.write(buf, 0, bytesRead);
                                                                //dataOut.writeBytes(buf);
                                                                }
                                                        
                                                        for(int k = 0; k<b.length;k++){
                                                                dataOut.writeBytes(b[k]+"\n");
                                                        }
                                                        dataOut.flush();
                                                        
                                                } catch (IOException e1) {
                                                        e1.printStackTrace();
                                                }
                                               
                                                reponse = "226 \n";
                                               
                                        } catch (IOException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                                reponse = "500 \n";
                                        }
               
                               
                               
                        }else{
                                reponse = "550 Fichier non existant\n"; //Reponse : "Fichier non existant"
                        }
                       
                }else{ // Pas connecter
                        reponse = "530 Not logged in\n";
                }
                
                try {
                                dataOut.close();
                                socket2.close();
                        } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                
                return reponse;
        }
       
        public String processSTOR(String message, String fichier) {
                String reponse;
                File file = new File(this.repertoire +"/"+ message);
               
                if(this.connecter){ //Connecter
                        try {
                                file.createNewFile();
                                FileOutputStream out = new FileOutputStream(this.repertoire + message);
                                out.write(fichier.getBytes());
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                        reponse = "226 Closing data connection. Requested file action successful\n";
                       
                }else{ // Pas connecter
                        reponse = "532 Need account for storing files\n";
                }
                return reponse;
               
        }
       
        /*public String processLIST() {
                String reponse;
                File folder = new File(this.repertoire);
                String[] listeFichier = folder.list();
                
                BufferedOutputStream bos = null;
                DataOutputStream dataOut = null;
                
                InetAddress ipClientFTP = this.socket.getInetAddress();
                Socket socket2 = null;
                try {
                        socket2 = new Socket(ipClientFTP,this.portPassiv);
                } catch (IOException e2) {
                        // TODO Auto-generated catch block
                        e2.printStackTrace();
                }
                                 
                try {
        
                        ostream.write("150 begin\n");
                        ostream.flush();
                        
                        bos = new BufferedOutputStream(socket2.getOutputStream());
                        dataOut = new DataOutputStream (bos);
                } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                }               
                        
                for(int i = 0; i< listeFichier.length;i++){
                        try {
                                                        
                                dataOut.writeBytes(listeFichier[i]+"\n");
                                dataOut.flush();
                        } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }                       
                }
                
                try {
                        dataOut.close();
                        socket2.close();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                
                return "226 end \n";
        }*/
        
        public String processLIST() {
                String reponse;
               // File folder = new File(this.repertoire);
               // String[] listeFichier = folder.list();
                
                BufferedOutputStream bos = null;
                DataOutputStream dataOut = null;
                
                InetAddress ipClientFTP = this.socket.getInetAddress();
                Socket socket2 = null;
                try {
                        socket2 = new Socket(ipClientFTP,this.portPassiv);
                } catch (IOException e2) {
                        e2.printStackTrace();
                }
                                 
                try {
        
                        ostream.write("150 begin\n");
                        ostream.flush();
                        
                        bos = new BufferedOutputStream(socket2.getOutputStream());
                        dataOut = new DataOutputStream (bos);
                } catch (IOException e1) {
                        e1.printStackTrace();
                }               
                        
               // for(int i = 0; i< listeFichier.length;i++){
                        try {
                                
                               String msg = contenuDossier(this.repertoire);

			                   /* File f = new File(this.repertoire+ "/" +listeFichier[i]);
			                    if(f.isDirectory()) msgLigne += "d"; else msgLigne +="-";
			                   
			                    Path path = Paths.get(f.getCanonicalPath());
			                    Set<PosixFilePermission> set = Files.getPosixFilePermissions(path);
			                    msgLigne += PosixFilePermissions.toString(set);                     
			                    
			                    msgLigne += " 1";
			                    
			
			                    path = Paths.get(f.getCanonicalPath());
			                    msgLigne += " " + Files.getOwner(path).toString();
			                    msgLigne += " " + Files.getOwner(path).toString();
			                    
			                    msgLigne += " " + f.length();
			                    
			                    SimpleDateFormat sdf = new SimpleDateFormat("MM. dd H:mm");
			                    Date d = new Date(f.lastModified());
			                    
			                    msgLigne += " " + sdf.format(d);
			                    
			                    msgLigne += " " + listeFichier[i];
			                    
			                    System.out.println(msgLigne);*/
                    
                                dataOut.writeBytes(msg);
                                dataOut.flush();
                                
                        } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }                       
               // }
                
                try {
                        dataOut.close();
                        socket2.close();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                
                return "226 end \n";
        }
        
        
        public String contenuDossier(String adresse){
        	File folder = new File(adresse);
            String[] listeFichier = folder.list();
            
            String adresseClient = adresse.substring(this.repertoire.length());
            
            String contenu = "";
            for(int i = 0; i< listeFichier.length;i++){
                        
                try {
		            File f = new File(adresse+ "/" +listeFichier[i]);
		            if(f.isDirectory()) contenu += "d"; else contenu +="-";
		           
		            Path path = Paths.get(f.getCanonicalPath());
		            Set<PosixFilePermission> set = Files.getPosixFilePermissions(path);
		            contenu += PosixFilePermissions.toString(set);                     
		            
		            contenu += " 1";
		            
		
		            path = Paths.get(f.getCanonicalPath());
		           
		            contenu += " " + Files.getOwner(path).toString();
	
		            contenu += " " + Files.getOwner(path).toString();
		            
		            contenu += " " + f.length();
		            
		            SimpleDateFormat sdf = new SimpleDateFormat("MM. dd H:mm");
		            Date d = new Date(f.lastModified());
		            
		            contenu += " " + sdf.format(d);
		            
		            contenu += " " + adresseClient+"/"+listeFichier[i] + "\n";
		            
		            if(f.isDirectory()){
		            	contenu += contenuDossier(adresse+ "/" +listeFichier[i]);
		            }
		            
		            System.out.println(contenu);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
            }
            
            
            return contenu;
        }
       
        public String processPWD(){
                return "257 "+this.repertoireClient+"\n";
        }
       
        public String processCWD(String msgTransfert){
                String reponse;
                this.repertoireClient = msgTransfert;
                //File folder = new File(this.repertoire);
                //TODO demander la connection
                //this.processLIST();
                
                reponse = "250 \n";
                return reponse;
        }
       
        public String processQUIT() {
                String reponse;
               
                if(this.connecter){
                        //DETRUIRE L'OBJET COURANT
                        reponse = "221";
                }else{
                        reponse = ""; //?
                }
                return reponse;
        }

        public String processEPRT(String msgTransfert) {
                //EPRT |2|::1|58736|
                //http://www.serv-u.com/respcode.asp?cmd=EPRT&prod=su
               
                String[] msg = msgTransfert.split("\\|");
                this.portPassiv =  Integer.parseInt(msg[3]);            
                return "200 " + msg[3] + " \n";
        }
       
        public String processEPSV() {
                String reponse;
               
                if(this.connecter){ //Connecter
                        this.mode = 1;//Mode passif
                        reponse = "200 Mode passif\n";
                }else{ // Pas connecter
                        reponse = "532 Need account for storing files\n";
                }
                return reponse;
               
        }
       
        public String processPORT(String msg) {
                String reponse;
                if(msg != null){
                        this.port = Integer.parseInt(msg);
                        reponse = "200 PORT successful\n";
                }else{
                        reponse = "400 no port\n";
                }
               
                return reponse;
               
        }
       
        public String processTYPE(String msg) {
                String reponse;
                if(msg != null){
                        this.type = msg;
                        reponse = "200 Type set to "+msg+"\n";
                }else{
                        reponse = "400 no port\n";
                }
               
                return reponse;
               
        }
}